/*
 * BitReader.cpp
 *
 *  Created on: 22/10/2011
 *      Author: agustin
 */

#include "BitReader.h"

BitReader::BitReader(const char* source) {
	// Esta estructura se usa para determinar el tamaño optimo del buffer.
	stat(source, &stats);

	if (-1 == (fd = open(source, O_RDONLY))) {
		perror("open() ");
		exit(1);
	}
	if (NULL
			== (buffer = (unsigned char*) malloc(
					stats.st_blksize * sizeof(unsigned char)))) {
		close(fd);
		perror("malloc() ");
		exit(1);
	}

	this->buff_bit = 0;
	this->bytes_read = 0;

	//inicio el buffer leyendo un bloque
	bytes_read += read(fd, buffer, stats.st_blksize);
	this->buff_bit = 0;
}

bool BitReader::bufferLeido() {
	return (this->buff_bit >= (stats.st_blksize * 8));
}

unsigned char BitReader::leerBit() {
	if (this->bufferLeido()) {
		if (bytes_read < stats.st_size) {
			bytes_read += read(fd, buffer, stats.st_blksize);
			this->buff_bit = 0;
		} else {
			perror("Se trata de leer mas allá del EOF");
			exit(1);
		}
	}

	div_t divresult;
	divresult = div(this->buff_bit, 8);

	int byte_buff = divresult.quot;
	int offset_buff = divresult.rem;

	//incremento el numero del proximo bit a escribir del buffer;
	this->buff_bit++;

	return (buffer[byte_buff] & (1 << offset_buff));
}

//La posicion debe ser en BITS
void BitReader::posicionar(size_t pos) {

//Calculo el bloque en que me debo posicionar
	div_t divresult;
	divresult = div(pos, (stats.st_blksize * 8));

	size_t block = divresult.quot;
	this->buff_bit = divresult.rem;

	this->bytes_read = block * stats.st_blksize;

//Me posiciono en el bloque calculado
	lseek(fd, block * stats.st_blksize, 0);

//Leo el buffer
	bytes_read += read(fd, buffer, stats.st_blksize);

}

void BitReader::cerrar() {
	//Reinicio el buffer
	for (int i = 0; i < stats.st_blksize; i++) {
		buffer[i] = buffer[i] & 0x0;
	}
	this->buff_bit = 0;

	close(fd);
}

void BitReader::abrir(char* source) {
	// Esta estructura se usa para determinar el tamaño optimo del buffer.
	stat(source, &stats);

	if (-1 == (fd = open(source, O_RDONLY))) {
		perror("open() ");
		exit(1);
	}
	if (NULL
			== (buffer = (unsigned char*) malloc(
					stats.st_blksize * sizeof(unsigned char)))) {
		close(fd);
		perror("malloc() ");
		exit(1);
	}

	this->buff_bit = 0;
	this->bytes_read = 0;

	//inicio el buffer leyendo un bloque
	bytes_read += read(fd, buffer, stats.st_blksize);
	this->buff_bit = 0;
}

BitReader::~BitReader() {
	free(buffer);
	close(fd);
}
